/*
 * Mat2.cpp
 *
 *  Created on: 20.09.2009
 *  Author: Christoph Caks
 */

// this file is included by its header file to satisfy the compiler
#include "types/Mat2.h"

namespace mehari {
namespace common {

template <typename Real>
Mat2<Real>::Mat2() {
	this->data[0] = 0;
	this->data[1] = 0;
	this->data[2] = 0;
	this->data[3] = 0;
}

template <typename Real>
Mat2<Real>::Mat2( const Real r0, const Real r1, const Real r2, const Real r3 ) {
	this->data[0] = r0;
	this->data[1] = r1;
	this->data[2] = r2;
	this->data[3] = r3;
}

template <typename Real>
Mat2<Real>::Mat2( const Real matrix[4] ) {
	this->data[0] = matrix[0];
	this->data[1] = matrix[1];
	this->data[2] = matrix[2];
	this->data[3] = matrix[3];
}

template <typename Real>
Mat2<Real>::Mat2( const Mat2& m2 ) {
	this->data[0] = m2.data[0];
	this->data[1] = m2.data[1];
	this->data[2] = m2.data[2];
	this->data[3] = m2.data[3];
}

template <typename Real>
Mat2<Real>::~Mat2() {
}

template <typename Real>
const Real* Mat2<Real>::operator [] ( int iRow ) const {
	return &data[iRow*2];
}

template <typename Real>
Real* Mat2<Real>::operator [] ( int iRow ) {
	return &data[iRow*2];
}

template <typename Real>
Real Mat2<Real>::operator () ( int iRow, int iCol ) const {
	return data[iRow*2+iCol];
}

template <typename Real>
Real& Mat2<Real>::operator () ( int iRow, int iCol ) {
	return data[iRow*2+iCol];
}

template <typename Real>
void Mat2<Real>::setRow( int iRow, const Vec2<Real>& v2Val ) {
	data[iRow*2 + 0] = v2Val.data[0];
	data[iRow*2 + 1] = v2Val.data[1];
}

template <typename Real>
void Mat2<Real>::setCol( int iCol, const Vec2<Real>& v2Val ) {
	data[0*2 + iCol] = v2Val.data[0];
	data[1*2 + iCol] = v2Val.data[1];
}

template <typename Real>
Vec2<Real> Mat2<Real>::getRow( int iRow ) const {
	return Vec2<Real>( data[iRow*2 + 0], data[iRow*2 + 1] );
}

template <typename Real>
Vec2<Real> Mat2<Real>::getCol( int iCol ) const {
	return Vec2<Real>( data[0*2 + iCol], data[1*2 + iCol] );
}

template <typename Real>
void Mat2<Real>::setZero() {
	for ( int i = 0; i < 4; i++ ) {
		data[i] = 0;
	}
}

template <typename Real>
void Mat2<Real>::setIdentity() {
	data[0] = 1;
	data[1] = 0;
	data[2] = 0;
	data[3] = 1;
}

template <typename Real>
Mat2<Real>& Mat2<Real>::operator = ( const Mat2<Real>& m2Rhs ) {
	data[0] = m2Rhs.data[0];
	data[1] = m2Rhs.data[1];
	data[2] = m2Rhs.data[2];
	data[3] = m2Rhs.data[3];
}

// arithmetic operations
template <typename Real>
Mat2<Real> Mat2<Real>::operator + ( const Mat2<Real>& mRhs ) const {
	return Mat2<Real>( 	data[0] + mRhs.data[0], data[1] + mRhs.data[1],
						data[2] + mRhs.data[2], data[3] + mRhs.data[3] );
}

template <typename Real>
Mat2<Real> Mat2<Real>::operator - ( const Mat2<Real>& mRhs ) const {
	return Mat2<Real>( 	data[0] - mRhs.data[0], data[1] - mRhs.data[1],
						data[2] - mRhs.data[2], data[3] - mRhs.data[3] );
}

template <typename Real>
Mat2<Real> Mat2<Real>::operator * ( const Real rRhs ) const {
	return Mat2<Real>(	data[0] * rRhs, data[1] * rRhs,
						data[2] * rRhs, data[3] * rRhs );
}

template <typename Real>
Mat2<Real> Mat2<Real>::operator / ( const Real rRhs ) const {
	return Mat2<Real>(	data[0] / rRhs, data[1] / rRhs,
						data[2] / rRhs, data[3] / rRhs );
}


template <typename Real>
Mat2<Real> Mat2<Real>::operator += ( const Mat2<Real>& mRhs ) {
	data[0] += mRhs.data[0];
	data[1] += mRhs.data[1];
	data[2] += mRhs.data[2];
	data[3] += mRhs.data[3];
}

template <typename Real>
Mat2<Real> Mat2<Real>::operator -= ( const Mat2<Real>& mRhs ) {
	data[0] -= mRhs.data[0];
	data[1] -= mRhs.data[1];
	data[2] -= mRhs.data[2];
	data[3] -= mRhs.data[3];
}

template <typename Real>
Mat2<Real> Mat2<Real>::operator *= ( const Real rRhs ) {
	data[0] *= rRhs;
	data[1] *= rRhs;
	data[2] *= rRhs;
	data[3] *= rRhs;
}

template <typename Real>
Mat2<Real> Mat2<Real>::operator /= ( const Real rRhs ) {
	data[0] /= rRhs;
	data[1] /= rRhs;
	data[2] /= rRhs;
	data[3] /= rRhs;
}

// TODO comparison operations
template <typename Real>
bool Mat2<Real>::operator == ( const Mat2<Real>& m2Rhs ) const {
	return data[0] == m2Rhs.data[0] && data[1] == m2Rhs[2] && data[2] == m2Rhs[2] && data[3] == m2Rhs[3];
}

template <typename Real>
bool Mat2<Real>::operator != ( const Mat2<Real>& m2Rhs ) const {
	return !( data[0] == m2Rhs.data[0] && data[1] == m2Rhs[2] && data[2] == m2Rhs[2] && data[3] == m2Rhs[3] );
}

// TODO geometric operations

template <typename Real>
Vec2<Real> Mat2<Real>::operator * ( const Vec2<Real>& v2Rhs ) const {
	return Vec2<Real>( data[0] * v2Rhs.data[0] + data[2] * v2Rhs.data[1], data[1] * v2Rhs.data[0] + data[3] * v2Rhs.data[1] );
}

// other
template <typename Real>
Mat2<Real> Mat2<Real>::transpose() const {
	return Mat2<Real>(	data[0], data[2],
						data[1], data[3] );
}

template <typename Real>
Mat2<Real> Mat2<Real>::inverse() const {
	// TODO implement inverse
	return Mat2<Real>();
}

template <typename Real>
Mat2<Real> Mat2<Real>::adjoint() const {
	// TODO implement adjoint
	return Mat2<Real>();
}

template <typename Real>
Real Mat2<Real>::determinant() const {
	// TODO implement determinant
	return Mat2<Real>();

}

} // namespace common
} // namespace mehari
